/**
 * 20220121：finalized by jordia
 */
import IncidentVertex from "./incident-vertex";
import Method from "../../common/method";

/**
 * 剪切面
 */
export default class FaceClipper {
    constructor() {
        this.w = 0;
        this.h = 0;
        this.numVertices = 0;
        this.numTmpVertices = 0;
        this.vertices = new Array(8);
        this.tmpVertices = new Array(8);
        for(let i=0;i<8;i++){
            this.vertices[i] = new IncidentVertex();
            this.tmpVertices[i] = new IncidentVertex();
        }
        this._fv0=new Float64Array(5);
    }
    _addScaledVert(s1,s2,v2,v1){
        let t = s1 / (s1 - s2);
        let d21=Method.subArray(v2,v1,this._fv0,0,0,0,5);
        Method.scaleArray(d21,t,d21,0,0,5);
        Method.addArray(v1,d21,this.tmpVertices[this.numTmpVertices++].elements,0,0,0,5);
    }
    _setVertex(s1,s2,v1,v2){
        if(s1 > 0 && s2 > 0) {
            Method.copyElements(v1,this.tmpVertices[this.numTmpVertices++].elements,0,0,5);
        } else if(s1 > 0 && s2 <= 0) {
            Method.copyElements(v1,this.tmpVertices[this.numTmpVertices++].elements,0,0,5);
            this._addScaledVert(s1,s2,v2,v1);
        } else if(s1 <= 0 && s2 > 0) {
            this._addScaledVert(s1,s2,v2,v1);
        }
    }
    clip() {
        let _g = 0, _g1 = this.numVertices;
        while(_g < _g1) {
            let i = _g++;
            let v1 = this.vertices[i].elements;
            let v2 = this.vertices[(i + 1) % _g1].elements;
            let s1 = this.w + v1[0];
            let s2 = this.w + v2[0];
            this._setVertex(s1,s2,v1,v2);
        }
        let tmp = this.vertices;
        this.vertices = this.tmpVertices;
        this.tmpVertices = tmp;
        this.numVertices = this.numTmpVertices;
        this.numTmpVertices = 0;
        let _g2 = 0, _g3 = this.numVertices;
        while(_g2 < _g3) {
            let i = _g2++;
            let v1 = this.vertices[i].elements;
            let v2 = this.vertices[(i + 1) % this.numVertices].elements;
            let s1 = this.w - v1[0];
            let s2 = this.w - v2[0];
            this._setVertex(s1,s2,v1,v2);
        }
        let tmp1 = this.vertices;
        this.vertices = this.tmpVertices;
        this.tmpVertices = tmp1;
        this.numVertices = this.numTmpVertices;
        this.numTmpVertices = 0;
        let _g4 = 0, _g5 = this.numVertices;
        while(_g4 < _g5) {
            let i = _g4++;
            let v1 = this.vertices[i].elements;
            let v2 = this.vertices[(i + 1) % this.numVertices].elements;
            let s1 = this.h + v1[1];
            let s2 = this.h + v2[1];
            this._setVertex(s1,s2,v1,v2);
        }
        let tmp2 = this.vertices;
        this.vertices = this.tmpVertices;
        this.tmpVertices = tmp2;
        this.numVertices = this.numTmpVertices;
        this.numTmpVertices = 0;
        let _g6 = 0, _g7 = this.numVertices;
        while(_g6 < _g7) {
            let i = _g6++;
            let v1 = this.vertices[i].elements;
            let v2 = this.vertices[(i + 1) % this.numVertices].elements;
            let s1 = this.h - v1[1];
            let s2 = this.h - v2[1];
            this._setVertex(s1,s2,v1,v2);
        }
        let tmp3 = this.vertices;
        this.vertices = this.tmpVertices;
        this.tmpVertices = tmp3;
        this.numVertices = this.numTmpVertices;
        this.numTmpVertices = 0;
    }
    reduce() {
        if(this.numVertices < 4) {
            return;
        }
        let max1 = -1e65536, min1 = 1e65536;
        let max2 = -1e65536, min2 = 1e65536;
        let max1V = null, min1V = null;
        let max2V = null, min2V = null;
        let e1x = 1, e1y = 1;
        let e2x = -1, e2y = 1;
        let _g = 0, _g1 = this.numVertices;
        while(_g < _g1) {
            let v = this.vertices[_g++].elements;
            let dot1 = v[0] * e1x + v[1] * e1y;
            let dot2 = v[0] * e2x + v[1] * e2y;
            if(dot1 > max1) {
                max1 = dot1;
                max1V = v;
            }
            if(dot1 < min1) {
                min1 = dot1;
                min1V = v;
            }
            if(dot2 > max2) {
                max2 = dot2;
                max2V = v;
            }
            if(dot2 < min2) {
                min2 = dot2;
                min2V = v;
            }
        }
        Method.copyElements(max1V,this.tmpVertices[this.numTmpVertices++].elements,0,0,5);
        Method.copyElements(max2V,this.tmpVertices[this.numTmpVertices++].elements,0,0,5);
        Method.copyElements(min1V,this.tmpVertices[this.numTmpVertices++].elements,0,0,5);
        Method.copyElements(min2V,this.tmpVertices[this.numTmpVertices++].elements,0,0,5);
        let tmp = this.vertices;
        this.vertices = this.tmpVertices;
        this.tmpVertices = tmp;
        this.numVertices = this.numTmpVertices;
        this.numTmpVertices = 0;
    }
}